 /*******************************************************************************
  * Copyright (c) 2005, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
  * Contributors:
  * IBM Corporation - initial API and implementation
  *******************************************************************************/
 package org.eclipse.ui.internal.dialogs;

 import java.util.ArrayList ;
 import java.util.List ;

 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.Path;
 import org.eclipse.jface.dialogs.Dialog;
 import org.eclipse.jface.viewers.DoubleClickEvent;
 import org.eclipse.jface.viewers.ISelection;
 import org.eclipse.jface.viewers.IStructuredSelection;
 import org.eclipse.jface.viewers.StructuredSelection;
 import org.eclipse.jface.viewers.TreeViewer;
 import org.eclipse.jface.wizard.IWizardNode;
 import org.eclipse.jface.wizard.IWizardPage;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.graphics.Font;
 import org.eclipse.swt.layout.GridData;
 import org.eclipse.swt.layout.GridLayout;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Control;
 import org.eclipse.swt.widgets.Label;
 import org.eclipse.ui.IWorkbench;
 import org.eclipse.ui.IWorkbenchWizard;
 import org.eclipse.ui.activities.ITriggerPoint;
 import org.eclipse.ui.activities.WorkbenchActivityHelper;
 import org.eclipse.ui.dialogs.FilteredTree;
 import org.eclipse.ui.internal.WorkbenchMessages;
 import org.eclipse.ui.model.AdaptableList;
 import org.eclipse.ui.model.WorkbenchLabelProvider;
 import org.eclipse.ui.wizards.IWizardCategory;
 import org.eclipse.ui.wizards.IWizardDescriptor;

 /**
  * Abstract wizard page class from which an import or export wizard can be chosen.
  *
  * @since 3.2
  *
  */
 public abstract class ImportExportPage extends WorkbenchWizardSelectionPage{
     protected static final String DIALOG_SETTING_SECTION_NAME = "ImportExportPage."; //$NON-NLS-1$

     // tree viewer of wizard selections
 private TreeViewer treeViewer;
     
     /*
      * Class to create a control that shows a categorized tree of wizard types.
      */
     protected class CategorizedWizardSelectionTree {
         private final static int SIZING_LISTS_HEIGHT = 200;
         
         private IWizardCategory wizardCategories;
         private String message;
         private TreeViewer viewer;

         /**
          * Constructor for CategorizedWizardSelectionTree
          *
          * @param categories root wizard category for the wizard type
          * @param msg message describing what the user should choose from the tree.
          */
         protected CategorizedWizardSelectionTree(IWizardCategory categories, String msg){
             this.wizardCategories = categories;
             this.message = msg;
         }
         
         /**
          * Create the tree viewer and a message describing what the user should choose
          * from the tree.
          *
          * @param parent Composite on which the tree viewer is to be created
          * @return Comoposite with all widgets
          */
         protected Composite createControl(Composite parent){
             Font font = parent.getFont();

             // create composite for page.
 Composite outerContainer = new Composite(parent, SWT.NONE);
             outerContainer.setLayout(new GridLayout());
             outerContainer.setLayoutData(new GridData(GridData.FILL_BOTH));
             outerContainer.setFont(font);

             Label messageLabel = new Label(outerContainer, SWT.NONE);
             if (message != null) {
                 messageLabel.setText(message);
             }
             messageLabel.setFont(font);

             createFilteredTree(outerContainer);
             layoutTopControl(viewer.getControl());

             return outerContainer;
         }
         
         /**
          * Create the categorized tree viewer.
          *
          * @param parent
          */
         private void createFilteredTree(Composite parent){
             // Create a FilteredTree for the categories and wizards
 FilteredTree filteredTree = new FilteredTree(parent, SWT.SINGLE | SWT.H_SCROLL
                     | SWT.V_SCROLL | SWT.BORDER, new WizardPatternFilter());
             viewer = filteredTree.getViewer();
             filteredTree.setFont(parent.getFont());

             viewer.setContentProvider(new WizardContentProvider());
             viewer.setLabelProvider(new WorkbenchLabelProvider());
             viewer.setComparator(DataTransferWizardCollectionComparator.INSTANCE);
             
             ArrayList inputArray = new ArrayList ();
             boolean expandTop = false;

             if (wizardCategories != null) {
                 if (wizardCategories.getParent() == null) {
                     IWizardCategory [] children = wizardCategories.getCategories();
                     for (int i = 0; i < children.length; i++) {
                         inputArray.add(children[i]);
                     }
                 } else {
                     expandTop = true;
                     inputArray.add(wizardCategories);
                 }
             }

             // ensure the category is expanded. If there is a remembered expansion it will be set later.
 if (expandTop) {
                 viewer.setAutoExpandLevel(2);
             }

             AdaptableList input = new AdaptableList(inputArray);
             
             // filter wizard list according to capabilities that are enabled
 viewer.addFilter(new WizardActivityFilter());
             
             viewer.setInput(input);
         }

         /**
          *
          * @return the categorized tree viewer
          */
         protected TreeViewer getViewer(){
             return viewer;
         }

         /**
          * Layout for the given control.
          *
          * @param control
          */
         private void layoutTopControl(Control control) {
             GridData data = new GridData(GridData.FILL_BOTH);

             int availableRows = DialogUtil.availableRows(control.getParent());

             //Only give a height hint if the dialog is going to be too small
 if (availableRows > 50) {
                 data.heightHint = SIZING_LISTS_HEIGHT;
             } else {
                 data.heightHint = availableRows * 3;
             }

             control.setLayoutData(data);
         }
     }
     
     /**
      * Constructor for import/export wizard page.
      *
      * @param aWorkbench current workbench
      * @param currentSelection current selection
      */
     protected ImportExportPage(IWorkbench aWorkbench, IStructuredSelection currentSelection){
         super("importExportPage", aWorkbench, currentSelection, null, null); //$NON-NLS-1$
 setTitle(WorkbenchMessages.Select);
     }
     
     /*
      * (non-Javadoc)
      * @see org.eclipse.jface.dialogs.IDialogPage#createControl(org.eclipse.swt.widgets.Composite)
      */
     public void createControl(Composite parent) {
         Font font = parent.getFont();
     
         // create composite for page.
 Composite outerContainer = new Composite(parent, SWT.NONE);
         outerContainer.setLayout(new GridLayout());
         outerContainer.setLayoutData(new GridData(GridData.FILL_BOTH));
         outerContainer.setFont(font);

         Composite comp = createTreeViewer(outerContainer);
         
         Dialog.applyDialogFont(comp);
         
         restoreWidgetValues();
     
         setControl(outerContainer);
         
        initialize();
     }

     /**
      * Create the tree viewer from which a wizard is selected.
      */
     protected abstract Composite createTreeViewer(Composite parent);
     
     /**
      * Method to call when an item in one of the lists is double-clicked.
      * Shows the first page of the selected wizard or expands a collapsed
      * tree.
      * @param event
      */
     protected void treeDoubleClicked(DoubleClickEvent event){
         ISelection selection = event.getViewer().getSelection();
         IStructuredSelection ss = (IStructuredSelection) selection;
         listSelectionChanged(ss);
         
         Object element = ss.getFirstElement();
         TreeViewer v = (TreeViewer)event.getViewer();
         if (v.isExpandable(element)) {
             v.setExpandedState(element, !v.getExpandedState(element));
         } else if (element instanceof WorkbenchWizardElement) {
             if (canFlipToNextPage()) {
                 getContainer().showPage(getNextPage());
             }
         }
         getContainer().showPage(getNextPage());
     }
     
     /*
      * Update the wizard's message based on the given (selected) wizard element.
      */
     private void updateSelectedNode(WorkbenchWizardElement wizardElement){
         setErrorMessage(null);
         if (wizardElement == null) {
             updateMessage();
             setSelectedNode(null);
             return;
         }

         setSelectedNode(createWizardNode(wizardElement));
         setMessage(wizardElement.getDescription());
     }
     
     /*
      * Update the wizard's message based on the currently selected tab
      * and the selected wizard on that tab.
      */
     protected void updateMessage(){
         TreeViewer viewer = getTreeViewer();
         if (viewer != null){
             ISelection selection = viewer.getSelection();
             IStructuredSelection ss = (IStructuredSelection) selection;
             Object sel = ss.getFirstElement();
             if (sel instanceof WorkbenchWizardElement){
                 updateSelectedNode((WorkbenchWizardElement)sel);
             }
             else{
                 setSelectedNode(null);
             }
         } else {
             setMessage(null);
         }
     }
     
     /*
      * Method to call whenever the selection in one of the lists has changed.
      * Updates the wizard's message to relect the description of the currently
      * selected wizard.
      */
     protected void listSelectionChanged(ISelection selection){
         setErrorMessage(null);
         IStructuredSelection ss = (IStructuredSelection) selection;
         Object sel = ss.getFirstElement();
         if (sel instanceof WorkbenchWizardElement){
             WorkbenchWizardElement currentWizardSelection = (WorkbenchWizardElement) sel;
             updateSelectedNode(currentWizardSelection);
         } else {
             updateSelectedNode(null);
         }
     }

     /*
      * Create a wizard node given a wizard's descriptor.
      */
     private IWizardNode createWizardNode(IWizardDescriptor element) {
         return new WorkbenchWizardNode(this, element) {
             public IWorkbenchWizard createWizard() throws CoreException {
                 return wizardElement.createWizard();
             }
         };
     }
     
     /**
      * Uses the dialog store to restore widget values to the values that they
      * held last time this wizard was used to completion.
      */
     protected void restoreWidgetValues() {
         updateMessage();
     }

     /**
      * Expands the wizard categories in this page's category viewer that were
      * expanded last time this page was used. If a category that was previously
      * expanded no longer exists then it is ignored.
      */
     protected void expandPreviouslyExpandedCategories(String setting, IWizardCategory wizardCategories, TreeViewer viewer) {
         String [] expandedCategoryPaths = getDialogSettings()
                 .getArray(setting);
         if (expandedCategoryPaths == null || expandedCategoryPaths.length == 0) {
             return;
         }

         List categoriesToExpand = new ArrayList (expandedCategoryPaths.length);

         if (wizardCategories != null) {
             for (int i = 0; i < expandedCategoryPaths.length; i++) {
                 IWizardCategory category = wizardCategories
                         .findCategory(new Path(expandedCategoryPaths[i]));
                 if (category != null) {
                     categoriesToExpand.add(category);
                 }
             }
         }

         if (!categoriesToExpand.isEmpty()) {
             viewer.setExpandedElements(categoriesToExpand.toArray());
         }

     }

     /**
      * Selects the wizard category and wizard in this page that were selected
      * last time this page was used. If a category or wizard that was
      * previously selected no longer exists then it is ignored.
      */
     protected void selectPreviouslySelected(String setting, IWizardCategory wizardCategories, final TreeViewer viewer) {
         String selectedId = getDialogSettings().get(setting);
         if (selectedId == null) {
             return;
         }

         if (wizardCategories == null) {
             return;
         }

         Object selected = wizardCategories.findCategory(new Path(
                 selectedId));

         if (selected == null) {
             selected = wizardCategories.findWizard(selectedId);

             if (selected == null) {
                 // if we cant find either a category or a wizard, abort.
 return;
             }
         }

         viewer.setSelection(new StructuredSelection(selected), true);
     }
  
     /**
      * Stores the collection of currently-expanded categories in this page's
      * dialog store, in order to recreate this page's state in the next
      * instance of this page.
      */
     protected void storeExpandedCategories(String setting, TreeViewer viewer) {
         Object [] expandedElements = viewer.getExpandedElements();
         List expandedElementPaths = new ArrayList (expandedElements.length);
         for (int i = 0; i < expandedElements.length; ++i) {
             if (expandedElements[i] instanceof IWizardCategory) {
                 expandedElementPaths
                         .add(((IWizardCategory) expandedElements[i])
                                 .getPath().toString());
             }
         }
         getDialogSettings().put(setting,
                 (String []) expandedElementPaths
                         .toArray(new String [expandedElementPaths.size()]));
     }

     /**
      * Stores the currently-selected element in this page's dialog store, in
      * order to recreate this page's state in the next instance of this page.
      */
     protected void storeSelectedCategoryAndWizard(String setting, TreeViewer viewer) {
         Object selected = ((IStructuredSelection) viewer
                 .getSelection()).getFirstElement();

         if (selected != null) {
             if (selected instanceof IWizardCategory) {
                 getDialogSettings().put(setting,
                         ((IWizardCategory) selected).getPath()
                                 .toString());
             } else {
                 // else its a wizard
 getDialogSettings().put(setting,
                         ((IWizardDescriptor) selected).getId());
             }
         }
     }
     
     /**
      * When Finish is pressed, write widget values to the dialog store so
      * that they will persist into the next invocation of the wizard page.
      *
      */
     public void saveWidgetValues(){
         // do nothing by default - subclasses should override
 }
     
     /*
      * (non-Javadoc)
      * @see org.eclipse.jface.wizard.IWizardPage#getNextPage()
      */
     public IWizardPage getNextPage() {
         ITriggerPoint triggerPoint = getTriggerPoint();
         
         if (triggerPoint == null || WorkbenchActivityHelper.allowUseOf(triggerPoint, getSelectedNode())) {
             return super.getNextPage();
         }
         return null;
     }

     /**
      * Get the trigger point for the wizard type, if one exists.
      *
      * @return the wizard's trigger point
      */
     protected ITriggerPoint getTriggerPoint(){
         return null; // default implementation
 }
     
     /**
      * Set the tree viewer that is used for this wizard selection page.
      *
      * @param viewer
      */
     protected void setTreeViewer(TreeViewer viewer){
         treeViewer = viewer;
     }
     
     /**
      * Get the tree viewer that is used for this wizard selection page.
      *
      * @return tree viewer used for this wizard's selection page
      */
     protected TreeViewer getTreeViewer(){
         return treeViewer;
     }
     
     /**
      * Perform any initialization of the wizard page that needs to be done
      * after widgets are created and main control is set.
      */
     protected void initialize(){
         // do nothing by default
 }
 }

